package model.xml;

import java.io.FileNotFoundException;
import java.io.IOException;

import java.net.URL;

import java.util.ArrayList;
import java.util.List;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import model.Camera;
import model.GameContext;
import model.MapConstants;
import model.MapEnum;
import model.ModelComponent;
import model.components.StageComponent;
import model.components.StageComponentFactory;
import model.stages.StageEnum;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
/**
 *
 * @author thiago.barreto
 *
 */
public class XMLComponentParser {

	DocumentBuilder builder;
	Document document = null;
	Integer stageSize = null;
	StageComponentFactory scFactory;

	public XMLComponentParser() throws ParserConfigurationException{
		DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
		scFactory = new StageComponentFactory();
		builder = dbf.newDocumentBuilder();
	}

	/**
	 *
	 * @param stageEnum
	 * @return Document
	 */
	public Document buildDocument(StageEnum stageEnum){
		if(document == null){
			try {
				URL url = null;
				url = getClass().getClassLoader().getResource(getXMLFilePath(stageEnum.getName()));
				document = builder.parse(url.toString());

			} catch (SAXException e) {
				e.printStackTrace();
			}catch (FileNotFoundException e) {
				e.printStackTrace();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		return document;
	}

	/**
	 *
	 * @param tagPaiXml
	 * @return Lista de ModelComponents
	 * @throws Exception
	 */
	public List<ModelComponent> Parse(MapEnum currentPart) throws Exception{
		List<ModelComponent> list = new ArrayList<ModelComponent>();
		document = buildDocument(GameContext.getGameState().getStage());
		String currentXmlPart = currentPart.getXmlPart();
		NodeList nodeInicio = document.getElementsByTagName(currentXmlPart);
		for(int i = 0; i < nodeInicio.getLength();  i++){
			Element element = (Element)nodeInicio.item(i);
			List<Element> elementList = getChildElements(element);
			return generateStageComponentList(elementList, currentPart);
		}

		return list;
	}

	/**
	 * Le e retorna um List de elementos
	 * @param elem
	 * @return elementList
	 * @throws Exception
	 */
	private List<Element> getChildElements( Element element) throws Exception {
    	List<Element> elementList = new ArrayList<Element>();
    	for(StageComponentEnum value : StageComponentEnum.values()){
    		Element child = null;
    		NodeList children = element.getElementsByTagName( value.getTagName() );
            if( children != null ){
            	for(int i = 0; i < children.getLength(); i++){
            		child = (Element) children.item(i);
            		if( child != null ){
                    	elementList.add(child);
                    }
            	}
            }
    	}
        return elementList;
    }

	/**
	 *
	 * @param elementList
	 * @return
	 */
    private List<ModelComponent> generateStageComponentList(List<Element> elementList, MapEnum currentPart){
    	List<ModelComponent> componentList = new ArrayList<ModelComponent>();

    	for(Element element : elementList){
    		StageComponent component = scFactory.getComponent(element, currentPart);
	    	componentList.add(component);
    	}
    	return componentList;
    }

    /**
     * Retorna o atributo 'size' lido no xml do stage atual
     * @return int
     */
	public int getStageSize() {
		if(null == stageSize){
			document = buildDocument(GameContext.getGameState().getStage());
			NodeList mainNode = document.getElementsByTagName("phase");
			Element mainElement = (Element)mainNode.item(0);
			stageSize = Integer.valueOf(mainElement.getAttribute("size"));
		}
		return stageSize;
	}

	/**
	 * Retorna o path do arquivo xml a ser lido
	 * @param fileWithoutExtension
	 * @return String
	 */
	public String getXMLFilePath(String fileWithoutExtension){
		return "model/xml/xmlstages/".concat(fileWithoutExtension.concat(".xml"));
	}

	/**
	 * Retorna o Enum que representa a posicoa do jogador no mapa
	 * @return MapEnum
	 */
	public MapEnum verifyMapPosition(int playerDirection){
		if(playerDirection > 0){
			int limit = Camera.RIGTH_LIMIT;
				//limit = Camera.LEFT_LIMIT;
			if(limit > MapConstants.PART9)
				return MapEnum.PART10;
			if(limit > MapConstants.PART8)
				return MapEnum.PART9;
			if(limit > MapConstants.PART7)
				return MapEnum.PART8;
			if(limit > MapConstants.PART6)
				return MapEnum.PART7;
			if(limit > MapConstants.PART5)
				return MapEnum.PART6;
			if(limit > MapConstants.PART4)
				return MapEnum.PART5;
			if(limit > MapConstants.PART3)
				return MapEnum.PART4;
			if(limit > MapConstants.PART2)
				return MapEnum.PART3;
			if(limit > MapConstants.PART1)
				return MapEnum.PART2;
		}else{
			//FIXME
			int limit = Camera.LEFT_LIMIT;
			if(limit > MapConstants.PART9)
				return MapEnum.PART10;
			if(limit > MapConstants.PART8)
				return MapEnum.PART9;
			if(limit > MapConstants.PART7)
				return MapEnum.PART8;
			if(limit > MapConstants.PART6)
				return MapEnum.PART7;
			if(limit > MapConstants.PART5)
				return MapEnum.PART6;
			if(limit > MapConstants.PART4)
				return MapEnum.PART5;
			if(limit > MapConstants.PART3)
				return MapEnum.PART4;
			if(limit > MapConstants.PART2)
				return MapEnum.PART3;
			if(limit > MapConstants.PART1)
				return MapEnum.PART2;
		}
		return MapEnum.PART1;
	}

}
